﻿using KongMing.Project.Entity.Business;
using KongMing.Project.Entity.Common;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace KongMing.Project.Common.Sdk
{
    public static class JwtAuthTokenHelper
    {
        /// <summary>
        /// 生成 Jwt Token令牌
        /// </summary>
        public static (string, int) CreateJwtAuthToken(JwtConfig _jwtConfig,SysUser user)
        {
            // 有效载荷
            var claims = new Claim[]
            {
               new Claim("UserId",user.UserId),//自定义类型的信息 
               new Claim("Account",user.Account),
               new Claim(ClaimTypes.Name, user.Name)//固定类型的信息
            };

            #region 加密算法加密
            SigningCredentials creds = default;
            if (_jwtConfig.KeySymmetryType == 0)
            {//对称可逆加密
                //秘钥
                SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtConfig.SecurityKey));
                //将秘钥通过加密算法加密
                creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            }
            else
            {//非对称可逆加密
                string keyDir = Directory.GetCurrentDirectory();
                if (TryGetKeyParameters(keyDir, true, out RSAParameters keyParams) == false)
                {
                    keyParams = GenerateAndSaveKey(keyDir);
                }
                creds = new SigningCredentials(new RsaSecurityKey(keyParams), SecurityAlgorithms.RsaSha256Signature);
            }
            #endregion

            #region 设置jwt授权参数
            JwtSecurityToken token = new JwtSecurityToken(
             issuer: _jwtConfig.Issuer,
             audience: _jwtConfig.Audience,
             claims: claims,
             expires: DateTime.Now.AddMinutes(_jwtConfig.EffectiveMinutes),//token有效时间
             signingCredentials: creds);
            #endregion

            //最终生成的token
            string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
            return (returnToken, _jwtConfig.KeySymmetryType);
        }

        #region 非对称加密相关
        /// <summary>
        /// 从本地文件中读取用来签发 Token 的 RSA Key
        /// </summary>
        /// <param name="filePath">存放密钥的文件夹路径</param>
        /// <param name="withPrivate"></param>
        /// <param name="keyParameters"></param>
        /// <returns></returns>
        public static bool TryGetKeyParameters(string filePath, bool withPrivate, out RSAParameters keyParameters)
        {
            string filename = withPrivate ? "key.json" : "key.public.json";
            string fileTotalPath = Path.Combine(filePath, filename);
            keyParameters = default;
            if (!File.Exists(fileTotalPath))
            {
                return false;
            }
            else
            {
                keyParameters = JsonConvert.DeserializeObject<RSAParameters>(File.ReadAllText(fileTotalPath));
                return true;
            }
        }
        /// <summary>
        /// 生成并保存 RSA 公钥与私钥
        /// </summary>
        /// <param name="filePath">存放密钥的文件夹路径</param>
        /// <returns></returns>
        public static RSAParameters GenerateAndSaveKey(string filePath, bool withPrivate = true)
        {
            RSAParameters publicKeys, privateKeys;
            using (var rsa = new RSACryptoServiceProvider(2048))//即时生成
            {
                try
                {
                    privateKeys = rsa.ExportParameters(true);
                    publicKeys = rsa.ExportParameters(false);
                }
                finally
                {
                    rsa.PersistKeyInCsp = false;
                }
            }
            File.WriteAllText(Path.Combine(filePath, "key.json"), JsonConvert.SerializeObject(privateKeys));
            File.WriteAllText(Path.Combine(filePath, "key.public.json"), JsonConvert.SerializeObject(publicKeys));
            return withPrivate ? privateKeys : publicKeys;
        }
        #endregion
    }
}
